
#include "Base.h"

#include <string>
#include <vector>

#include "FPSMonitoringComponent.h"
#include "Entities/BaseEntity.h"
#include "Entities/ComponentTypeEnum.h"
#include "Game/Game.h"
#include "Sprite/SpriteRenderer.h"
#include "Sprite/SpriteTypes.h"
#include "Assets/AssetManager.h"
#include "Maths/Matrix3.h"
#include "Maths/Matrix4.h"
#include "Resources/ResourceManager.h"
#include "Graphics/Color.h"
#include "EventHandler/EventHandler.h"
#include "StringUtils.h"
#include "Entities/Components/TransformComponent.h"
#include "Game/Line2DRendererComponent.h"
#include "Game/GameInfo.h"
#include "Tools/DebugSystem.h"
#include "Maths/Math.h"
#include "Maths/Random.h"

#include <Memory/DebugNew.h>


namespace CasaEngine
{

/**
 * 
 */
FPSMonitoringComponent::FPSMonitoringComponent(BaseEntity* pEntity_)
	: Component(pEntity_, FPSMONITORING),
	m_pTransform(NULL),
	m_pLineRenderer(NULL),
	pDebugSystem(NULL),
	m_uiMaxNbData(10)
{
	registerEventFunc(this, &FPSMonitoringComponent::OnFPSChange);

	/* //Test debug
	m_FPSData.push_back(30);
	m_FPSData.push_back(35);
	m_FPSData.push_back(60);
	m_FPSData.push_back(40);
	m_FPSData.push_back(45);
	m_FPSData.push_back(70);
	m_FPSData.push_back(10);
	m_FPSData.push_back(60);
	m_FPSData.push_back(50);
	m_iFPSMin = 10;
	m_iFPSMax = 70;
	*/

	m_iFPSMin = MaxInt;
	m_iFPSMax = MinInt;
	m_iThresholdMin = 30;
	m_iThresholdMax = 60;
}

/**
 * 
 */
FPSMonitoringComponent::~FPSMonitoringComponent()
{
}

/**
 * 
 */
void FPSMonitoringComponent::Initialize()
{
	m_pTransform = GetEntity()->GetComponentMgr()->GetComponent<TransformComponent>();
	CASAENGINE_ASSERT(m_pTransform != NULL && "FPSMonitoringComponent::Initialize() can't find the TransformComponent. Please add it before add a FPSMonitoringComponent");

	m_pLineRenderer = Game::Instance()->GetGameComponent<Line2DRendererComponent>();
	CASAENGINE_ASSERT(m_pLineRenderer != NULL && "FPSMonitoringComponent::Initialize() can't find the Line2DRendererComponent.");

	pDebugSystem = Game::Instance()->GetGameComponent<DebugSystem>();
	CASAENGINE_ASSERT(pDebugSystem != NULL && "FPSMonitoringComponent::Initialize() can't find the DebugSystem.");
}

/**
 * 
 */
void FPSMonitoringComponent::Update(const GameTime& /*gameTime_*/)
{
	CASAENGINE_ASSERT(m_pLineRenderer != NULL);

	//Todo : compute this only when data is updated
	const int width = 200, height = 100;
	const int padding = 5;
	float startPercent, endPercent;
	float colorInterval = static_cast<float>(m_iThresholdMax - m_iThresholdMin);

	Vector2F pos(m_pTransform->GetWorldMatrix().GetTranslation().x,
		m_pTransform->GetWorldMatrix().GetTranslation().y);
	Vector2F start, end;	

	//axe vertical
	start = end = pos;
	start.x += padding;
	start.y += height - padding;
	end.x += padding;
	end.y += padding;
	m_pLineRenderer->AddLine(start, CColor::White, end, CColor(255,255,255,0));
	
	//axe horizontal
	end = start;
	end.x += width - padding;
	m_pLineRenderer->AddLine(start, CColor::White, end, CColor(255,255,255,0));

	start = end = pos;
	start.x += padding;

	if (m_FPSData.size() == 1)
	{		
		start.y += (height - padding) / 2.0f;
		end.x += width;
		end.y += (height - padding) / 2.0f;

		startPercent = static_cast<float>(m_FPSData[0] - m_iThresholdMin) / colorInterval;
		Clamp<float, float, float>(startPercent, 0.0f, 1.0f);

		CColor color(255 - static_cast<unsigned char>(255.0f * startPercent),
			0 - static_cast<unsigned char>(-255.0f * startPercent),
			0 - static_cast<unsigned char>(0.0f * startPercent));

		m_pLineRenderer->AddLine(start, color, end, color);
	}
	else if (m_FPSData.size() > 0)
	{
		float interval = static_cast<float>(m_iFPSMax - m_iFPSMin);				
		float step = static_cast<float>(width) / static_cast<float>(m_FPSData.size() - 1);		

		end.x += padding + step;

		for (std::vector<int>::const_iterator it = m_FPSData.cbegin();
			it != (m_FPSData.cend() - 1);
			it++)
		{			
			if (interval == 0.0f)
			{
				startPercent = 0.5f;
				endPercent = 0.5f;
			}
			else
			{
				//Y position invert
				startPercent = 1.0f - ((*it) - m_iFPSMin) / interval;
				endPercent = 1.0f - ((*(it + 1)) - m_iFPSMin) / interval;
			}

			start.y = pos.y + startPercent * (height - padding);
			end.y = pos.y + endPercent * (height - padding);

			//Color
			startPercent = static_cast<float>((*it) - m_iThresholdMin) / colorInterval;
			Clamp<float, float, float>(startPercent, 0.0f, 1.0f);
			endPercent = static_cast<float>((*(it + 1)) - m_iThresholdMin) / colorInterval;
			Clamp<float, float, float>(endPercent, 0.0f, 1.0f);

			CColor startColor(255 - static_cast<unsigned char>(255.0f * startPercent),
				0 - static_cast<unsigned char>(-255.0f * startPercent),
				0 - static_cast<unsigned char>(0.0f * startPercent));

			CColor endColor(255 - static_cast<unsigned char>(255.0f * endPercent),
				0 - static_cast<unsigned char>(-255.0f * endPercent),
				0 - static_cast<unsigned char>(0.0f * endPercent));

			m_pLineRenderer->AddLine(start, startColor, end, endColor);

			start.x += step;
			end.x += step;
		}
	}	
}

/**
 * 
 */
/*void FPSMonitoringComponent::HandleEvent(const Event* pEvent_)
{

}*/

/**
 * 
 */
void FPSMonitoringComponent::Write(std::ostream& /*os*/) const
{

}

/**
 * 
 */
void FPSMonitoringComponent::Read (std::ifstream& /*is*/)
{

}

/**
 * 
 */
void FPSMonitoringComponent::OnFPSChange( const FPSChangeEvent* pEvent_ )
{
	int fps = pEvent_->FPS(); // RandInt(30, 60);
	m_iFPSMin = MinOf(fps, m_iFPSMin);
	m_iFPSMax = MaxOf(fps, m_iFPSMax);

	if (m_FPSData.size() > m_uiMaxNbData)
	{
		m_FPSData.erase(m_FPSData.begin());
	}
	
	m_FPSData.push_back(fps);
}

} // namespace CasaEngine
